/* 
 *	JFTableVectorConfiguration
 *	Written by Joe Freeman, NeXT Systems Engineering
 *
 *	A list of these configuration objects is fed to a JFTableViewLoader
 *	to tell it what ivars and titles map into a DBTableView
 */

#import "JFTableVectorConfiguration.h"
#import <ansi/ctype.h>
#import <objc/objc-runtime.h>

@interface JFTableVectorConfiguration(Private)

- buildCachedInfo:sender;

@end

@implementation JFTableVectorConfiguration(Private)

/*======================================================================
 *	Private Methods
 *======================================================================*/

/* rebuild the selector and slot number stuff for performance reasons */
- buildCachedInfo:sender
{
    char tmpName[80];
    
    if (ivarName && *ivarName && template){
    	/* support either - ivarName or - getIvarName methods on get */
    	ivarInfo = class_getInstanceVariable(template, ivarName);
	getMethod = sel_getUid(ivarName);
	if (!getMethod){
		strcpy(tmpName,"get");
		strcat(tmpName,ivarName);
		tmpName[3] = toupper(tmpName[3]);
		getMethod = sel_getUid(tmpName);
	}
    	/* now try and figure out the setMethod name 
	 * try -setIvarName: or -ivarName: 
	 */
	strcpy(tmpName,"set");
	strcat(tmpName,ivarName);
	strcat(tmpName,":");
	tmpName[3] = toupper(tmpName[3]);
	setMethod = sel_getUid(tmpName)	;
	if (!setMethod){
		strcpy(tmpName,ivarName);
		strcat(tmpName,":");
		setMethod = sel_getUid(tmpName);
	}
    }
    return self;
}
@end

@implementation JFTableVectorConfiguration


/*======================================================================
 *	designated initializer
 *======================================================================*/

- init
{
    [super init];
    kindOfStringTable = NO;
    return self;
}

- initDataClassName:(const char *)aString 
	titleName:(const char *)newTitle 
	ivarName:(const char *)newIvar
{
    [self init];
    [self setDataClassName:aString];
    [self setTitle:newTitle];
    [self setIvarName:newIvar];
    return self;
}

/*======================================================================
 *	set up methods for this configuration object
 *======================================================================*/

- setDataClassName:(const char *)aString
{
    if (!aString)
    	templateName = NXUniqueString("");
    else
    	templateName = NXUniqueString(aString);
    if (objc_lookUpClass(aString)){
    	template =  objc_lookUpClass(aString);
	kindOfStringTable = [template isKindOfClassNamed:"NXStringTable"];
	[self buildCachedInfo:self];
    }
    return self;
}

- setTitle:(const char *)newTitle
{
    if (newTitle)
    	title = NXUniqueString(newTitle);
    else 
    	title = "";
    return self;
}

- setIvarName:(const char *)newIvar
{
    if (newIvar)
    	ivarName = NXUniqueString(newIvar);
    else
    	ivarName = "";
    [self buildCachedInfo:self];
    return self;
}

- (const char *)dataClassName;
{
    return templateName;
}


- (const char *)title
{
    return title;
}

- (const char *)ivarName
{
    return ivarName;
}


/*======================================================================
 *	archiving support (for the palette!)
 *======================================================================*/

- awake
{
    [self setDataClassName: templateName];	/* force cache rebuild */
    return self;
}

- read:(NXTypedStream *)typedStream
{
    [super read:typedStream];
    
    NXReadType(typedStream,"%",&templateName);
    NXReadType(typedStream,"%",&title);
    NXReadType(typedStream,"%",&ivarName);
   
    return self;
}
- write:(NXTypedStream *)typedStream
{
    [super write:typedStream];
    
    NXWriteType(typedStream,"%",&templateName);
    NXWriteType(typedStream,"%",&title);
    NXWriteType(typedStream,"%",&ivarName);
    
    return self;
}



/*======================================================================
 *	use this thing to transfer data from dbvalues to datastore objects
 *======================================================================*/

/*
 * Load up the DBValue object (aValue) from the portion of the 
 * dataObject specified by this configuration object
 */
- getValueFromObject:dataObject into:aValue
{
    /* we may have dynamicly loaded the data class after we init'd */
    if (!template)
    	[self setDataClassName:templateName];

    if (kindOfStringTable)
    	[aValue setStringValue:(char*)[dataObject valueForStringKey:ivarName]];
    else if (!ivarInfo || !getMethod)
    	[aValue setStringValue:"???"];
    /* Get that run time religion */
    else if (ivarInfo->ivar_type[0] == 'f')
    	[aValue setFloatValue:  ( (float (*)(id, SEL))
                [dataObject methodFor:getMethod] )(dataObject, getMethod)];
    else if (ivarInfo->ivar_type[0] == 'd')
    	[aValue setDoubleValue:  ( (double (*)(id, SEL))
                [dataObject methodFor:getMethod] )(dataObject, getMethod)];
    else if (ivarInfo->ivar_type[0] == 'i')
    	[aValue setIntValue:  ( (int (*)(id, SEL))
                [dataObject methodFor:getMethod] )(dataObject, getMethod)];
    else if (ivarInfo->ivar_type[0] == '*')
    	[aValue setStringValue:	(char *)[dataObject perform: getMethod]];
    else if (ivarInfo->ivar_type[0] == '[' &&
    	ivarInfo->ivar_type[strlen(ivarInfo->ivar_type)-2] == 'c')
    	[aValue setStringValue:	(char *)[dataObject perform: getMethod]];
    else 
    	[aValue setStringValue:""];
    return self;
}

/*
 * save the dbvalue object into the portion of the data object specified by
 * this configuration object 
 */
- setValueForObject:dataObject from:aValue
{
	id (* fConvert)(id, SEL, float);
	id (* dConvert)(id, SEL, double);
	id (* iConvert)(id, SEL, int);
	char *oldString;

    /* we may have dynamicly loaded the data class after we init'd */
    if (!template)
    	[self setDataClassName:templateName];

    if (kindOfStringTable) {
    	oldString = [dataObject insertKey:(const void *)ivarName 
		value:(void *)NXCopyStringBuffer([aValue stringValue])];
///	if (malloc_size(oldString)>0) 
///		NXFree(oldString);
    } else if (!ivarInfo || !setMethod)
    	return nil;
    /* Get that run time religion */
    else if (ivarInfo->ivar_type[0] == 'f') {
	fConvert = (id (*)(id, SEL, float))[dataObject methodFor: setMethod];
	fConvert(dataObject,setMethod,[aValue floatValue]);
    } else if (ivarInfo->ivar_type[0] == 'd') {
	dConvert = (id (*)(id, SEL, double))[dataObject methodFor: setMethod];
    	dConvert(dataObject,setMethod,[aValue doubleValue]);
    } else if (ivarInfo->ivar_type[0] == 'i') {
	iConvert = (id (*)(id, SEL, int))[dataObject methodFor: setMethod];
    	iConvert(dataObject,setMethod,[aValue intValue]);
    } else if (ivarInfo->ivar_type[0] == '*')
    	[dataObject perform:setMethod with:(id)[aValue stringValue]];
    else if (ivarInfo->ivar_type[0] == '[' &&
    	ivarInfo->ivar_type[strlen(ivarInfo->ivar_type)-2] == 'c')
    	[dataObject perform:setMethod with:(id)[aValue stringValue]];
    return self;
}


@end
